package com.express.gateway.verticle;

import com.express.gateway.common.CommonCons;
import com.express.gateway.common.EventBusTopicConst;
import com.express.gateway.common.GatewayAttribute;
import com.express.gateway.common.ResultFormat;
import com.express.gateway.common.util.PathUtil;
import com.express.gateway.manage.auth.ClientStaticAuth;
import com.express.gateway.manage.auth.UserAuthUtil;
import com.express.gateway.manage.enums.ContentTypeEnum;
import com.express.gateway.manage.enums.StatusCodeEnum;
import com.express.gateway.manage.handler.ApiConstructHandler;
import com.express.gateway.manage.handler.AppConstructHandler;
import com.express.gateway.manage.handler.FreeMarkerTemplateHandler;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Promise;
import io.vertx.core.file.impl.FileResolverImpl;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.core.spi.file.FileResolver;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.handler.*;
import io.vertx.ext.web.sstore.ClusteredSessionStore;
import io.vertx.ext.web.sstore.LocalSessionStore;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.File;

/**
 * Exp-Inlet页面客户端Verticle
 *
 * @author flower
 */
public class ClientWebVerticle extends AbstractVerticle {
    private static final Logger LOG = LogManager.getLogger(ClientWebVerticle.class);

    /**
     * 当前Vertx的唯一标识
     */
    private String vertxName;

    @Override
    public void start(Promise<Void> fut) throws Exception {
        LOG.info("start Client Manage Verticle");
        String vertxName = System.getProperty(CommonCons.KEY_VERTX, CommonCons.KEY_VERTX_NAME);
        ApiConstructHandler apiConstructHandler = new ApiConstructHandler(vertx, vertxName);
        AppConstructHandler appConstructHandler = new AppConstructHandler(vertx, vertxName);
        Router router = Router.router(vertx);
        router.route().handler(FaviconHandler.create(vertx, getFaviconPath()));
        router.route().handler(BodyHandler.create().setUploadsDirectory(getUploadsDirectory()));
        if (vertx.isClustered()) {
            router.route().handler(
                    SessionHandler.create(ClusteredSessionStore.create(vertx)).setSessionCookieName(GatewayAttribute.SESSION_COOKIE_NAME));
        } else {
            router.route().handler(SessionHandler.create(LocalSessionStore.create(vertx)).setSessionCookieName(GatewayAttribute.SESSION_COOKIE_NAME));
        }
        // 通过html的方式管理应用网关
        // TemplateEngine create = FreeMarkerTemplateEngine.create(vertx);
        // TemplateHandler tempHandler = TemplateHandler.create(create, getTemplateRoot(), CONTENT_VALUE_HTML_UTF8);
        TemplateHandler tempHandler = new FreeMarkerTemplateHandler(vertx, getTemplateRoot(), ContentTypeEnum.HTML_UTF8.val());
        router.getWithRegex(".+\\.ftl").handler(tempHandler);

        // 欢迎页
        router.route("/").handler(UserAuthUtil::welcome);
        router.route("/static/*")
                .handler(StaticHandler.create(getStaticRoot()))
                .handler(ClientStaticAuth.create())
                .handler(UserAuthUtil::roleCheck);


        router.route("/login/in").handler(UserAuthUtil::loginIn);
        router.route("/login/out").handler(UserAuthUtil::loginOut);

        router.route("/static/login.html");
        // 查看系统信息
        router.route("/static/sys/info").handler(this::sysInfo);
        router.route("/static/sys/replaceIpList").handler(this::sysReplaceIpList);
        // Application相关
        router.route("/static/app/list").handler(appConstructHandler::appListTemp);
        router.route("/static/app/create").handler(appConstructHandler::appCreateTemp);
        router.route("/static/app/get/:name").handler(appConstructHandler::appDetailTemp);
        router.route("/static/app/add").handler(appConstructHandler::addAppAction);
        router.route("/static/app/update/:name").handler(appConstructHandler::appUpdateTemp);
        router.route("/static/app/update").handler(appConstructHandler::updateAppAction);
        router.route("/static/app/del/:name").handler(appConstructHandler::delAppAction);
        router.route("/static/app/online/:name").handler(appConstructHandler::deployAppAction);
        router.route("/static/app/offline/:name").handler(appConstructHandler::unDeployAppAction);
        // API相关
        router.route("/static/api/list/:appName").handler(apiConstructHandler::apiListTemp);
        router.route("/static/api/create/:name").handler(apiConstructHandler::apiCreateTemp);
        router.route("/static/api/get/:name").handler(apiConstructHandler::apiDetailTemp);
        router.route("/static/api/add").handler(apiConstructHandler::addApiAction);
        router.route("/static/api/update/:name").handler(apiConstructHandler::apiUpdateTemp);
        router.route("/static/api/update").handler(apiConstructHandler::updateApiAction);
        router.route("/static/api/del/:appName/:apiName").handler(apiConstructHandler::delApiAction);
        router.route("/static/api/start/all/:appName").handler(apiConstructHandler::startAllApiAction);
        router.route("/static/api/start/:apiName").handler(apiConstructHandler::startApiAction);
        router.route("/static/api/stop/:appName/:apiName").handler(apiConstructHandler::stopApiAction);

        router.route("/static/trackInfo/:appName/:apiName").handler(this::getTrackInfo);

        vertx.createHttpServer().requestHandler(router).listen(config().getInteger("clientPort", 5256), res -> {
            if (res.succeeded()) {
                LOG.info("The ClientWebVerticle Running on port 5256");
                fut.complete();
            } else {
                LOG.error("The ClientWebVerticle start fail!");
                fut.fail(res.cause());
            }
        });
    }

    /**
     * 查看系统信息
     *
     * @param rct
     */
    public void sysInfo(RoutingContext rct) {
        LOG.info("[user : {}] 执行查看运行状态...", rct.session().<String>get(CommonCons.KEY_USER_NAME));
        HttpServerResponse response = rct.response().putHeader(CommonCons.CONTENT_TYPE, ContentTypeEnum.JSON_UTF8.val());
        vertx.eventBus().<JsonObject>request(EventBusTopicConst.SYSTEM_GET_INFO, null, reply -> {
            if (reply.succeeded()) {
                response.end(ResultFormat.format(StatusCodeEnum.C200, reply.result().body()));
                LOG.info("[user : {}] 执行查看运行状态...", rct.session().<String>get(CommonCons.KEY_USER_NAME));
            } else {
                response.end(ResultFormat.format(StatusCodeEnum.C500, reply.cause().toString()));
                LOG.error("[user : {}] 查看运行状态 失败:{}", rct.session().<String>get(CommonCons.KEY_USER_NAME), reply.cause().toString());
            }
        });
    }

    /**
     * 更新黑名单地址
     *
     * @param rct
     */
    public void sysReplaceIpList(RoutingContext rct) {
        LOG.info("[user : {}] 执行添加IP黑名单...", rct.session().<String>get(CommonCons.KEY_USER_NAME));
        JsonArray array = new JsonArray();
        if (rct.body() != null) {
            array = rct.body().asJsonArray();
        }
        HttpServerResponse response = rct.response().putHeader(CommonCons.CONTENT_TYPE, ContentTypeEnum.JSON_UTF8.val());
        JsonObject param = new JsonObject().put("ipList", array);
        vertx.eventBus().<Integer>request(EventBusTopicConst.SYSTEM_BLACK_IP_REPLACE, param, reply -> {
            if (reply.succeeded()) {
                response.end(ResultFormat.format(StatusCodeEnum.C200, reply.result().body()));
                LOG.info("[user : {}] 执行添加IP黑名单 结果:{}", rct.session().<String>get(CommonCons.KEY_USER_NAME), reply.result().body());
            } else {
                response.end(ResultFormat.format(StatusCodeEnum.C500, reply.cause().toString()));
                LOG.error("[user : {}] 执行添加IP黑名单 失败:{}", rct.session().<String>get(CommonCons.KEY_USER_NAME), reply.cause().toString());
            }
        });
    }


    /**
     * 查看API监控信息
     *
     * @param rct
     */
    public void getTrackInfo(RoutingContext rct) {
        String appName = rct.request().getParam(CommonCons.KEY_APP_NAME);
        String apiName = rct.request().getParam(CommonCons.KEY_API_NAME);
        JsonObject body = new JsonObject();
        body.put(CommonCons.KEY_APP_NAME, appName);
        body.put(CommonCons.KEY_API_NAME, apiName);
        rct.response().putHeader(CommonCons.CONTENT_TYPE, ContentTypeEnum.JSON_UTF8.val());
        vertx.eventBus().<JsonObject>request( EventBusTopicConst.SYSTEM_GET_TRACK_INFO, body).onFailure(ex -> {
            rct.response().end(ResultFormat.format(StatusCodeEnum.C500, ex.getMessage()));
        }).onSuccess(rs -> {
            rct.response().end(ResultFormat.format(StatusCodeEnum.C200, rs.body()));
        });
    }


    /**
     * 获得客户端的 Favicon图标
     *
     * @return
     */
    public String getFaviconPath() {
        if (PathUtil.isJarEnv()) {
            //return "../conf/static/logo.png";
            return "static/logo.png";
        } else {
            return "static/logo.png";
        }
    }

    /**
     * 获得静态文件的根目录
     *
     * @return
     */
    public String getStaticRoot() {
        if (PathUtil.isJarEnv()) {
            LOG.info("is JAR file run, file path is '/static'");
            return "static";
        } else {
            LOG.info("is JAR file run, file path is '/static'");
            return "static";
        }
    }

    /**
     * 获得模板的路径
     *
     * @return
     */
    public String getTemplateRoot() {
        if (PathUtil.isJarEnv()) {
            FileResolver fileResolver = new FileResolverImpl();
            File file = fileResolver.resolveFile(new File(PathUtil.getPathString("templates")).getPath());
            return (file.getPath().startsWith("/") ? "" : "/") + file.getPath();
        } else {
            return "target/classes/templates";
        }

    }

    /**
     * 获得文件上传的文件夹路径
     *
     * @return
     */
    public String getUploadsDirectory() {
        if (PathUtil.isJarEnv()) {
            return "/temp/file-uploads";
        } else {
            return "file-uploads";
        }
    }
}
